#include "sceneController.h"
#include "view/camera/perspective_camera.h"

SceneController::SceneController(View* view,Model* model)
	: Controller(view,model){
	this->drag=false;
}

SceneController::~SceneController(){
}

void SceneController::mousePressed(int key,int state,float x ,float y){
	if(key==GLUT_LEFT_BUTTON && state==GLUT_DOWN){
		dragPos = Point(x,y);
		drag=true;
	}

	if(key==GLUT_LEFT_BUTTON && state==GLUT_UP)
		drag=false;
}

void SceneController::mouseMotion(float x ,float y){
	SceneView& pview = dynamic_cast<SceneView&>(*this->view);
	if(drag){
		Point dragDir = dragPos - Point(x,y);

		// Normalizar
		if(fabs(dragDir.x1)>0 && fabs(dragDir.x2)>0)
				dragDir = Point(dragDir.x1/fabs(dragDir.x1),dragDir.x2/fabs(dragDir.x2));
		else if(fabs(dragDir.x1)>0)
				dragDir = Point(dragDir.x1/fabs(dragDir.x1),0);
		else if(fabs(dragDir.x2)>0)
				dragDir = Point(0,dragDir.x2/fabs(dragDir.x2));

		// Los controladores de vistas ortogonales deben redefinir el mouse moution
		// de manera obligatoria o falla este cast.
		static_cast<PerspectiveCamera&>(pview.getCamera()).rotateLR(dragDir.x1*0.03f);
		static_cast<PerspectiveCamera&>(pview.getCamera()).rotateUD(-dragDir.x2*0.03f);

		dragPos = Point(x,y);
	}
}

void SceneController::specKeyboard(int key,int x ,int y){
	SceneModel& smodel = dynamic_cast<SceneModel&>(*model);
	Helicopter& heli = smodel.getHelicopter();
	switch(key){
		case GLUT_KEY_PAGE_UP:
			heli.accelerate(Helicopter::ascendAmount);
			break;
		case GLUT_KEY_PAGE_DOWN:
			heli.accelerate(Helicopter::descendAmount);
			break;
		case GLUT_KEY_UP:
			heli.accelerate(Helicopter::accelerateUpAmount);
			break;
		case GLUT_KEY_DOWN:
			heli.accelerate(Helicopter::accelerateDownAmount);
			break;
		case GLUT_KEY_LEFT:
			heli.accelerate(Helicopter::accelerateLeftAmount);
			break;
		case GLUT_KEY_RIGHT:
			heli.accelerate(Helicopter::accelerateRightAmount);
			break;
	}
}

void SceneController::keyboard(unsigned char key,float x ,float y){
	SceneModel& smodel = dynamic_cast<SceneModel&>(*model);
	Helicopter& heli = smodel.getHelicopter();
	SceneView& sview = dynamic_cast<SceneView&>(*view);

	switch(key){
		case 'z':
			sview.takeScreenshot();
			break;
		case 'q':
			heli.rotate(Helicopter::zRotationAmount);
			break;
		case 'e':
			heli.rotate(-Helicopter::zRotationAmount);
			break;
		case '1':
			smodel.setEnviron(SceneModel::DAY_ENVIRON);
			sview.notifyActivate();
			break;
		case '2':
			smodel.setEnviron(SceneModel::SUNSET_ENVIRON);
			sview.notifyActivate();
			break;
		case '3':
			smodel.setEnviron(SceneModel::NIGHT_ENVIRON);
			sview.notifyActivate();
			break;
		case '4':
			smodel.setEnviron(SceneModel::STORM_ENVIRON);
			sview.notifyActivate();
			break;
		case '5':
			smodel.setEnviron(SceneModel::MNT_ENVIRON);
			sview.notifyActivate();
			break;
		case 'o':
			sview.addZoomFactor(0.005f);
			break;
		case 'p':
			sview.addZoomFactor(-0.005f);
			break;
		case 0x20:
			smodel.handleClamp();
			break;
		case 0x2B:
			heli.extendThread(Helicopter::threadExtensionAmount);
			break;
		case 0x2D:
			heli.shrinkThread(Helicopter::threadExtensionAmount);
			break;
	}
}

void SceneController::timer(int value){
	SceneModel& smodel = static_cast<SceneModel&>(*model);
	Rain& rain = smodel.getRain();
	SkyBox& sbox = smodel.getSkyBox();
	Point viewerCenter = getViewerCenter();

	if(smodel.getEnvironState()==SceneModel::STORM_ENVIRON){
		// Solo centro en x,y
		Point rainCenter = rain.getDimensions().center();
		rainCenter.x3 = 0;
		if(!(rainCenter==viewerCenter))
			rain.move(viewerCenter.x1-rainCenter.x1,viewerCenter.x2-rainCenter.x2,0);
	}

	Point sboxCenter = sbox.getDimensions().center();
	sboxCenter.x3 = 0;
	sbox.move(viewerCenter.x1-sboxCenter.x1,viewerCenter.x2-sboxCenter.x2,0);

	smodel.timer(value);
}

Point SceneController::getViewerCenter(){
	SceneView& pview = dynamic_cast<SceneView&>(*this->view);
	return pview.getCamera().getEye();
}

void SceneController::notifyActivate(){
	SceneView& sview = dynamic_cast<SceneView&>(*view);
	sview.notifyActivate();
}
